//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <linknode.h>
#include <usyscall.h>
#include <elapi.h>
#include <marshal.h>
#include <prxstub.h>
#include <_critsec.h>
#include <eladef.h>
#include <bootmods.h>
#include <stdlib.h>
#include <string.h>
#include <elacfg.h>
#include <ctype.h>
#include "CCallbackContext.h"
#include <rot.h>
#include <elacs.h>
#include <memspy.h>

#undef MEMORYSPY

_ELASTOS_NAMESPACE_USING

IKernel * g_pIKernel;
IProcess * g_pICurrentProcess;
CriticalSection g_moduleLock;
CriticalSection g_tlsLock;
CriticalSection g_staticObjectListLock;
CriticalSection g_processExitRoutineListLock;
EXTERN UInt32 g_uMainThreadStackTop;
Byte g_tlsTypes[TLS_TOTAL_SLOTS];
DLinkNode g_tlsAllocatedList;
DLinkNode g_tlsAllocatedNodes[TLS_TOTAL_SLOTS];
EXTERN_C const InterfaceID EIID_IProxy;
PInterface g_pMainCallbackContext = NULL;

EXTERN UInt32 GetCurrentThreadStackTop();
EXTERN void CleanUpThreadLocalSlots(UInt32 uStackTop);
EXTERN void CleanUpAllThreadsLocalSlots();

void FreeCurProcComponents();

INLINE UInt32 GetStackTop()
{
    int n;
    UInt32 StackTop;
    StackTop = ((UInt32)&n & ~(USER_STACK_ALIGN - 1)) + USER_STACK_ALIGN;
    if ((StackTop > THREAD_STACK_LIMIT) || (StackTop <= THREAD_STACK_BASE)) {
        SysGetThreadStackTop(&StackTop);
    }

    return StackTop;
}

static UInt32 s_uDelayLoopCount = 0;

static IKernel *GetIKernel()
{
    ECode ec;

    if (NULL == g_pIKernel) {
// TODO(mips): Because the Kernel was compiled by GNUC, but the Elastos was compiled by EVC
#ifdef _GNUC_MIPS_KERNEL_
        ec = _CSystem_FindRunningObject(L"E\0l\0a\0s\0t\0o\0s\0K\0e\0r\0n\0e\0l\0", (PInterface *)&g_pIKernel);
#else
        ec = _CSystem_FindRunningObject(L"ElastosKernel", (PInterface *)&g_pIKernel);
#endif
        if (FAILED(ec)) {
            printf("Cannot find server ElastosKernel, the ec = 0x%08x\n", ec);
            return NULL;
        }

        ec = g_pIKernel->GetDelayFactor((Int32*)&s_uDelayLoopCount);
        if (FAILED(ec)) {
            printf("Failed to get delay parameter, the ec = 0x%08x\n", ec);
            s_uDelayLoopCount = 0;
        }
    }

    return g_pIKernel;
}

struct ThreadQuitRoutineNode : public SLinkNode {
    ThreadQuitRoutineNode(void * pThis, void * pFunc) :
        m_delegate(EventHandler::Make(pThis, pFunc)) {}

    EventHandler m_delegate;
};

struct ProcessExitRoutineNode : public SLinkNode {
    ProcessExitRoutineNode(void * pThis, void * pFunc) :
        m_delegate(EventHandler::Make(pThis, pFunc)) {}

    EventHandler m_delegate;
};

class CThreadQuitContext : public IInterface {
public:
    CARAPI_(PInterface) Probe(REIID riid)
    {
        return NULL;
    }

    CARAPI_(UInt32) AddRef()
    {
        return m_ref.Increment();
    }

    CARAPI_(UInt32) Release()
    {
        Int32 ref = m_ref.Decrement();
        if (ref == 0) {
            delete this;
        }
        return ref;
    }

    CARAPI Aggregate(AggrType aggrType, PInterface pObject)
    {
        return E_NOT_IMPLEMENTED;
    }

    CARAPI GetDomain(PInterface *ppObj)
    {
        return E_NOT_IMPLEMENTED;
    }

    CThreadQuitContext()
    {
        m_quitRoutineList.Initialize();
        m_staticObjectList.Initialize();
    }

    virtual ~CThreadQuitContext()
    {
        // Delete the thread quit routine nodes
        register SLinkNode * pNode = m_quitRoutineList.First();
        while (pNode != &m_quitRoutineList) {
            pNode->Detach(&m_quitRoutineList);
            delete pNode;
            pNode = m_quitRoutineList.First();
        }

        // Clean up thread static objects
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
    }

    void DoAtQuit()
    {
        // Call thread quit routines and delete the routine nodes
        void * pThis, * pFunc;
        register SLinkNode * pNode = m_quitRoutineList.First();
        while (pNode != &m_quitRoutineList) {
            pThis = ((ThreadQuitRoutineNode *)pNode)->m_delegate.GetThisPtr();
            pFunc = ((ThreadQuitRoutineNode *)pNode)->m_delegate.GetFuncPtr();
            pNode->Detach(&m_quitRoutineList);
            delete pNode;

            ((PThreadQuitRoutine)pFunc)(pThis);

            pNode = m_quitRoutineList.First();
        }

        // Clean up thread static objects
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
    }

    ECode AddQuitRoutine(PThreadQuitRoutine pEntry, PVoid pUserData)
    {
        assert(pEntry);
        ThreadQuitRoutineNode * pNode = new ThreadQuitRoutineNode(
                pUserData, *(void **)&pEntry);
        if (!pNode) return E_OUT_OF_MEMORY;
        m_quitRoutineList.InsertFirst(pNode);
        return NOERROR;
    }

    ECode AddObject(PInterface pObject)
    {
        assert(pObject);
        StaticObject * pNode = new StaticObject(pObject);
        if (!pNode) return E_OUT_OF_MEMORY;
        m_staticObjectList.InsertNext(pNode);
        return NOERROR;
    }

private:
    SLinkNode m_quitRoutineList;
    SLinkNode m_staticObjectList;
    Interlocked m_ref;
};

class CProcessExitContext {
public:
    CProcessExitContext()
    {
        m_exitRoutineList.Initialize();
        m_staticObjectList.Initialize();
    }

    ~CProcessExitContext()
    {
        assert(m_exitRoutineList.IsEmpty() && m_staticObjectList.IsEmpty());
    }

    void DoAtExit()
    {
        // Call process exit routines and delete the routine nodes
        Void * pContext = _Elastos_CriticalSection_Enter(&g_processExitRoutineListLock);
        void * pThis, * pFunc;
        register SLinkNode * pNode = m_exitRoutineList.First();
        while (pNode != &m_exitRoutineList) {
            pThis = ((ProcessExitRoutineNode *)pNode)->m_delegate.GetThisPtr();
            pFunc = ((ProcessExitRoutineNode *)pNode)->m_delegate.GetFuncPtr();
            pNode->Detach(&m_exitRoutineList);
            delete pNode;
            _Elastos_CriticalSection_Leave(&g_processExitRoutineListLock, pContext);

            ((PProcessExitRoutine)pFunc)(pThis);

            pContext = _Elastos_CriticalSection_Enter(&g_processExitRoutineListLock);
            pNode = m_exitRoutineList.First();
        }
        _Elastos_CriticalSection_Leave(&g_processExitRoutineListLock, pContext);

        // Clean up process static objects
        pContext = _Elastos_CriticalSection_Enter(&g_staticObjectListLock);
        pNode = m_staticObjectList.First();
        while (pNode != &m_staticObjectList) {
            pNode->Detach(&m_staticObjectList);
            delete (StaticObject *)pNode;
            pNode = m_staticObjectList.First();
        }
        _Elastos_CriticalSection_Leave(&g_staticObjectListLock, pContext);
    }

    ECode AddExitRoutine(PProcessExitRoutine pEntry, PVoid pUserData)
    {
        assert(pEntry);
        ProcessExitRoutineNode * pNode = new ProcessExitRoutineNode(
                pUserData, *(void **)&pEntry);
        if (!pNode) return E_OUT_OF_MEMORY;

        Void * pContext = _Elastos_CriticalSection_Enter(&g_processExitRoutineListLock);
        m_exitRoutineList.InsertFirst(pNode);
        _Elastos_CriticalSection_Leave(&g_processExitRoutineListLock, pContext);

        return NOERROR;
    }

    ECode AddObject(PInterface pObject)
    {
        assert(pObject);
        StaticObject * pNode = new StaticObject(pObject);
        if (!pNode) return E_OUT_OF_MEMORY;

        Void * pContext = _Elastos_CriticalSection_Enter(&g_staticObjectListLock);
        m_staticObjectList.InsertNext(pNode);
        _Elastos_CriticalSection_Leave(&g_staticObjectListLock, pContext);

        return NOERROR;
    }

private:
    SLinkNode m_exitRoutineList;
    SLinkNode m_staticObjectList;
};

static CProcessExitContext s_processExitContext;

class CAppletContext : public IInterface {
public:
    CARAPI_(PInterface) Probe(REIID riid)
    {
        return NULL;
    }

    CARAPI_(UInt32) AddRef()
    {
        Int32 nRef = m_ref.Increment();
        return (UInt32)nRef;
    }

    CARAPI_(UInt32) Release()
    {
        Int32 nRef = m_ref.Decrement();
        if (nRef == 0) {
            delete this;
        }
        return nRef;
    }

    CARAPI Aggregate(AggrType aggrType, PInterface pObject)
    {
        return E_NOT_IMPLEMENTED;
    }

    CARAPI GetDomain(PInterface *ppObj)
    {
        return E_NOT_IMPLEMENTED;
    }

    CAppletContext():m_pApplet(NULL), m_bValid(TRUE), m_pThreadQuitContext(NULL)
    {
    }

    virtual ~CAppletContext()
    {
        m_bValid = FALSE;
        if (m_pApplet) {
            m_pApplet->Release();
        }
        if (m_pThreadQuitContext) {
            m_pThreadQuitContext->Release();
        }
    }

    ECode Initialize(IApplet* pApplet)
    {
        if (NULL == pApplet) return E_INVALID_ARGUMENT;
        if (m_pThreadQuitContext) return NOERROR;

        m_pThreadQuitContext = new CThreadQuitContext;
        if (!m_pThreadQuitContext) return E_OUT_OF_MEMORY;

        m_pThreadQuitContext->AddRef();

        pApplet->AddRef();
        m_pApplet = pApplet;

        return NOERROR;
    }

    ECode Uninitialize()
    {
        if (m_pThreadQuitContext) {
            m_pThreadQuitContext->DoAtQuit();
            m_pThreadQuitContext->Release();
            m_pThreadQuitContext = NULL;
        }
        return NOERROR;
    }

    ECode AddQuitRoutine(PThreadQuitRoutine pEntry, PVoid pUserData)
    {
        if (m_pThreadQuitContext) {
            return m_pThreadQuitContext->AddQuitRoutine(pEntry, pUserData);
        }
        return E_APPLET_ALREADY_FINISHED;
    }

    ECode AddObject(PInterface pObject)
    {
        if (m_pThreadQuitContext) {
            return m_pThreadQuitContext->AddObject(pObject);
        }
        return E_APPLET_ALREADY_FINISHED;
    }

    Boolean IsValid()
    {
        return m_bValid;
    }

public:
    IApplet* m_pApplet;
private:
    Interlocked m_ref;
    Boolean m_bValid;
    CThreadQuitContext* m_pThreadQuitContext;
};

ELAPI _Impl_CAppletContext_GetCurrent(PInterface* ppAppletContext)
{
    PInterface pAppletContext;

    if (ppAppletContext == NULL) return E_INVALID_ARGUMENT;

    ECode ec = _CThread_GetLocalObject(TL_APPLET_SLOT, &pAppletContext);
    if (FAILED(ec)) return ec;

    if (pAppletContext == NULL) return E_NOT_IN_ANY_APPLET;

    if (!((CAppletContext*)pAppletContext)->IsValid()) return E_APPLET_ALREADY_FINISHED;
    *ppAppletContext = pAppletContext;

    return NOERROR;
}

ELAPI _Impl_CAppletContext_Initialize(
    IApplet* pApplet)
{
    CAppletContext* pAppletContext = new CAppletContext;

    if (NULL == pAppletContext) return E_OUT_OF_MEMORY;

    ECode ec = ((CAppletContext*)pAppletContext)->Initialize(pApplet);
    if (FAILED(ec)) {
        delete pAppletContext;
        return ec;
    }

    pAppletContext->AddRef();
    ec = _CThread_SetLocalObject(TL_APPLET_SLOT, pAppletContext);
    if (FAILED(ec)) return ec;

    PInterface pCallbackContext = NULL;
    _Impl_CallbackSink_GetCallbackContext(&pCallbackContext);
    assert(pCallbackContext);
    ((CCallbackContext *)pCallbackContext)->m_Status = AppletStatus_Starting;

    _CThread_SetLocalObject(TL_ORG_CALLBACK_SLOT, pCallbackContext);

    return NOERROR;
}

ELAPI _Impl_CAppletContext_Uninitialize()
{
    PInterface pAppletContext = NULL;
    PInterface pCallbackContext = NULL;

    _Impl_CallbackSink_GetCallbackContext(&pCallbackContext);
    assert(pCallbackContext);
    ((CCallbackContext *)pCallbackContext)->m_Status = AppletStatus_Deceased;
    ((CCallbackContext *)pCallbackContext)->CancelAllCallbackEvents();
    pCallbackContext->Release();

    _CThread_SetLocalObject(TL_ORG_CALLBACK_SLOT, NULL);

    ECode ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec)) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return NOERROR;

    ec = ((CAppletContext*)pAppletContext)->Uninitialize();
    if (FAILED(ec)) return ec;

    return NOERROR;
}

class CCallbackRendezvous : public ICallbackRendezvous
{
public:
    CARAPI_(PInterface) Probe(REIID riid);
    CARAPI_(UInt32) AddRef();
    CARAPI_(UInt32) Release();

    CARAPI Aggregate(AggregateType type, PInterface pObj)
        { return E_NOT_IMPLEMENTED; }

    CARAPI GetDomain(PInterface *ppObj)
        { return E_NOT_IMPLEMENTED; }

    CCallbackRendezvous(
        PInterface pCallbackContext,
        ICallbackSink* pCallbackSink,
        Int32 eventId,
        Boolean* pbEventFlag,
        Boolean bNewCallback) :
            m_pCallbackContext(pCallbackContext),
            m_pCallbackSink(pCallbackSink),
            m_EventId(eventId),
            m_pbEventFlag(pbEventFlag),
            m_bNewCallback(bNewCallback)
    {
        if (m_pCallbackSink) m_pCallbackSink->AddRef();
    }

    virtual ~CCallbackRendezvous();

    CARAPI Wait(
            /* in */ Millisecond32 msTimeout,
            /* out */ WaitResult *result);

    PInterface                  m_pCallbackContext;
    ICallbackSink*              m_pCallbackSink;
    Int32                       m_EventId;
    Boolean*                    m_pbEventFlag;
    Boolean                     m_bNewCallback;
private:
    Interlocked                 m_cRef;
};

UInt32 CCallbackRendezvous::AddRef()
{
    Int32 nRef = m_cRef.Increment();
    return (UInt32)nRef;
}

UInt32 CCallbackRendezvous::Release()
{
    Int32 nRef = m_cRef.Decrement();

    if (0 == nRef) {
        delete this;
    }

    return nRef;
}

PInterface CCallbackRendezvous::Probe(REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)this;
    }
    return NULL;
}

CCallbackRendezvous::~CCallbackRendezvous()
{
    if (m_pCallbackSink) {
        if (m_bNewCallback) {
            PInterface pOrgCtx;
            _CThread_GetLocalObject(TL_CALLBACK_SLOT, &pOrgCtx);
            if (m_pCallbackContext) m_pCallbackContext->AddRef();
            _CThread_SetLocalObject(TL_CALLBACK_SLOT, m_pCallbackContext);
            m_pCallbackSink->RemoveCallback(
                                            m_EventId, EventHandler::Make(NULL, NULL));
            _CThread_SetLocalObject(TL_CALLBACK_SLOT, pOrgCtx);
        }
        m_pCallbackSink->Release();
    }
    if (m_pCallbackContext) m_pCallbackContext->Release();
}

ECode CCallbackRendezvous::Wait(
    Millisecond32 msTimeOut,
    WaitResult *result)
{

    ECode ec = _Impl_CallbackSink_WaitForCallbackEvent(
                            m_pCallbackContext,
                            msTimeOut,
                            result,
                            m_pbEventFlag,
                            0);

    return ec;
}

ELAPI _Impl_CCallbackRendezvous_New(
        PInterface pCallbackContext,
        ICallbackSink* pCallbackSink,
        CallbackEventId eventId,
        Boolean* pbEventFlag,
        Boolean bNewCallback,
        ICallbackRendezvous** ppICallbackRendezvous)
{
    if (NULL == ppICallbackRendezvous) return E_INVALID_ARGUMENT;
    *ppICallbackRendezvous = new CCallbackRendezvous(
                                    pCallbackContext,
                                    pCallbackSink,
                                    eventId,
                                    pbEventFlag,
                                    bNewCallback);
    if (*ppICallbackRendezvous == NULL) return E_OUT_OF_MEMORY;
    (*ppICallbackRendezvous)->AddRef();

    return NOERROR;
}

ELAPI _CApplet_GetCurrent(PInterface* ppApplet)
{
    PInterface pAppletContext = NULL;
    PInterface pApplet;
    ECode ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec)) return ec;

    pAppletContext->Release();

    pApplet = ((CAppletContext*)pAppletContext)->m_pApplet;
    pApplet->AddRef();

    *ppApplet = pApplet;

    return NOERROR;
}

ELAPI _CApplet_AtFinish(
            PThreadQuitRoutine pEntry,
            PVoid pUserData)
{
    ECode ec;
    PInterface pAppletContext = NULL;
    if (!pEntry) return E_INVALID_ARGUMENT;

    ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec) && E_NOT_IN_ANY_APPLET != ec) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return _CProcess_AtExit(pEntry, pUserData);

    return ((CAppletContext*)pAppletContext)->AddQuitRoutine(pEntry, pUserData);
}

ELAPI _CApplet_GetAllThreads(IObjectEnumerator** ppThreads)
{
    IApplet *pApplet;

    ECode ec = _CApplet_GetCurrent((PInterface *)&pApplet);
    if (FAILED(ec)) return ec;

    ec = pApplet->GetAllThreads(ppThreads);
    pApplet->Release();

    return ec;
}

ECode InitializeThreadInfo()
{
    IThread * pCurrentThread;
    ECode ec = GetIKernel()->GetCurrentThread(&pCurrentThread);
    if (SUCCEEDED(ec)) {
        _CThread_SetLocalObject(TL_THREAD_INFO_SLOT, pCurrentThread);
    }
    return ec;
}

void ThreadEntry(
            ECode (*pEntry)(void*),
            void *pArg)
{
#if defined(_arm)
    // The second argument is the alternative sp
    UInt32 *uSP = (UInt32 *)pArg;
    pEntry = (ECode (*)(void*))*(uSP + 1);
    pArg = (void *)*(uSP + 2);
#endif
    ExitCode ec = 0;
    PInterface pCallbackContext = NULL;
    PInterface pApplet = NULL;

    // TL_CALLBACK_SLOT and TL_APPLET_SLOT was derived from Parent Thread and
    // calls AddRef here. It will be automatically released when the current
    // thread is finished.
    _CThread_GetLocalObject(TL_CALLBACK_SLOT, &pCallbackContext);
    _CThread_GetLocalObject(TL_APPLET_SLOT, &pApplet);

    ec = InitializeThreadInfo();
    if (FAILED(ec)) {
        _CThread_Quit(ec);
    }

    ec = (*pEntry)(pArg);
    pCallbackContext = NULL;
    pApplet = NULL;

    _CThread_Quit(ec);
}

// ElAPI functions
//
extern CriticalSection g_marshalLock;

ELAPI _CSystem_RegisterRunningObject(
            WString name,
            PInterface pService)
{
    IStub  * pIStub;
    ECode ec;
    IProxy * pIProxy;
    oid_t oid;

    if (name.IsNull() || !pService) return E_INVALID_ARGUMENT;

    if (wcslen(name) > MAXIMUM_SERVICE_NAME_LENGTH) {
        return E_SERVICE_NAME_TOO_LONG;
    }

    pIProxy = (IProxy*)pService->Probe(EIID_IProxy);
    if (pIProxy) {
        ec = pIProxy->GetOid(&oid);
        if (SUCCEEDED(ec)) {
            ec = SysRegisterService(name, oid);
        }
    }
    else {
        ExportObject ex;
        ec = FindExportObject(pService, &ex);
        if (SUCCEEDED(ec)) {
            ec = SysRegisterService(name, ex.m_oid);
            ex.m_pIStub->Release();
        }
        else {
            Void * pContext = _Elastos_CriticalSection_Enter(&g_marshalLock);
            ec = CObjectStub::S_CreateObject(name, pService, &pIStub);
            _Elastos_CriticalSection_Leave(&g_marshalLock, pContext);
        }
    }
    return ec;
}

ELAPI _CSystem_FindRunningObject(
            WString name,
            PInterface *ppService)
{
    if (name.IsNull() || !ppService) {
        return E_INVALID_ARGUMENT;
    }

    InterfacePack iPack;
    ECode ec;
    PContext pContext;

    iPack.m_pClsEntry = 0;
    ec = SysResolveCommon(name, &iPack.m_oid, &iPack.m_clsid, \
                        &iPack.m_uIndex, (CIClassEntry **)&iPack.m_pClsEntry,\
                        &pContext);
    if (FAILED(ec)) {
        return ec;
    }

    iPack.m_pid = (CTX_USER_2_KERN  == pContext) ? KERNEL_PID : INVALID_PID;
    ec = StdUnmarshalInterface(&iPack, pContext, TRUE, ppService);

    return ec;
}

ELAPI _CSystem_WaitForRunningObject(
            WString name, Int32 timeout, WaitResult *pResult)
{
    if (name.IsNull() || NULL == pResult) return E_INVALID_ARGUMENT;

    void * pLock = _Elastos_SequencedContext_Leave();

    ECode ec = SysWaitService(name, timeout, pResult);

    _Elastos_SequencedContext_Enter(pLock);

    return ec;
}

ELAPI _CSystem_UnregisterRunningObject(
            WString name)
{
    if (name.IsNull()) return E_INVALID_ARGUMENT;
    return SysUnregisterCommon(name);
}

ELAPI _CSystem_GetMachineTime(
            SystemTime *pSystemTime)
{
    return GetIKernel()->GetSystemTime(pSystemTime);
}

ELAPI _CSystem_SetMachineTime(
            SystemTime systemTime)
{
    return GetIKernel()->SetSystemTime(systemTime);
}

ELAPI_(Millisecond32) _CSystem_GetElapsedTime()
{
    Millisecond32 ms;
    ECode ec = GetIKernel()->GetElapsedTime(&ms);
    if (FAILED(ec)) {
        ms = -1;
    }
    return ms;
}

ELAPI_(Millisecond32) _CSystem_GetIdleTime()
{
    Millisecond32 ms;
    ECode ec = GetIKernel()->GetIdleTime(&ms);
    if (FAILED(ec)) {
        ms = -1;
    }
    return ms;
}

ELAPI_(Int32) _CSystem_GetVersion()
{
    return ELASTOS_VERSION_HEX;
}

ELAPI _CSystem_GetGlobalMemorySizes(
            Int32 *pTotalPhysicalMemorySize,
            Int32 *pAvailablePhysicalMemorySize)
{
    return GetIKernel()->GetGlobalMemorySizes(
            pTotalPhysicalMemorySize, pAvailablePhysicalMemorySize);
}

ELAPI _CSystem_DebugPrint(
            WString string)
{
#ifndef ELASTOS_RC    
    return SysPrint(string);
#else
    return NOERROR;
#endif
}

ELAPI _EzGetVirKey(
            struct KBDStatus *pVirtulCode)
{
    return SysGetVirtualCode(pVirtulCode);
}

ELAPI _CSystem_Reboot()
{
    return SysReboot();
}

ELAPI _CSystem_QueryPerformanceCounter(
        _ELASTOS Int64 *pPerformanceCount)
{
    return SysQueryPerformanceCounter(pPerformanceCount, NULL);
}

ELAPI _CSystem_QueryPerformanceFrequency(
        _ELASTOS Int64 *pFrequency)
{
    return SysQueryPerformanceCounter(NULL, pFrequency);
}

ELAPI _CProcess_NewUnstarted(
            IProcess **ppProcess)
{
    return GetIKernel()->CreateProcess(ppProcess);
}

ELAPI _CProcess_New(
            WString name,
            WString args,
            IProcess **ppProcess)
{
    ECode ec;
    IProcess *pIProcess;

    ec = GetIKernel()->CreateProcess(&pIProcess);
    if (FAILED(ec)) return ec;

    ec = pIProcess->Start(name, args);
    if (SUCCEEDED(ec) && ppProcess) {
        *ppProcess = pIProcess;
    }
    else {
        pIProcess->Release();
    }

    return ec;
}

ELAPI _CSystem_GetAllProcesses(
            IObjectEnumerator **ppProcesses)
{
    return GetIKernel()->GetAllProcesses(ppProcesses);
}

ELAPI_(IProcess *) _CProcess_GetCurrent()
{
    assert(NULL != g_pICurrentProcess);

    return g_pICurrentProcess;
}

ELAPI_(void) _CProcess_Exit(
            ExitCode exitCode)
{
    exit(exitCode);
}

ELAPI_(void) _CProcess_Terminate(
            ExitCode exitCode)
{
    // Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    // Call process exit routines and clean up process static objects
    s_processExitContext.DoAtExit();

    CleanUpAllThreadsLocalSlots();

    FreeCurProcComponents();
    GetIKernel()->ExitProcess(exitCode);
    assert(0);
}

ELAPI _CProcess_AtExit(
        /* [in] */ PProcessExitRoutine pEntry,
        /* [in] */ PVoid pUserData)
{
    if (!pEntry) return E_INVALID_ARGUMENT;

    return s_processExitContext.AddExitRoutine(pEntry, pUserData);
}

static ECode LoadModule(
            WString wsName,
            ModuleLoadFlags flags,
            IModule **ppIModule)
{
    BufferOf_<Address, 512> eaDllEntries;
    Int32 i = 0;
    ECode ec;
    Boolean bIsLoaded;

    Void * pContext = _Elastos_CriticalSection_Enter(&g_moduleLock);

    ec = GetIKernel()->LoadModule(wsName, flags, &eaDllEntries, ppIModule, &bIsLoaded);
    if (FAILED(ec)) {
        _Elastos_CriticalSection_Leave(&g_moduleLock, pContext);
        return ec;
    }

    if (NOERROR == ec && bIsLoaded) {
        // eaDllEntries[i]          Address of DllMainCRTStartup
        // eaDllEntries[i + 1]      Image base
        while (eaDllEntries[i]) {
            assert(eaDllEntries[i + 1]);
            (*(_ELASTOS Boolean (__stdcall *)(PVoid, UInt32, PVoid))eaDllEntries[i])(
                (PVoid)eaDllEntries[i + 1], DLL_PROCESS_ATTACH, NULL);
            i += 2;
            if (i >= eaDllEntries.GetUsed()) break;
        }
    }

    _Elastos_CriticalSection_Leave(&g_moduleLock, pContext);

    return ec;
}


ELAPI _CModule_Load(
            WString name,
            ModuleLoadFlags flags,
            IModule **ppModule)
{
    ECode ec;
    WStringBuf_<256> esbpath;

    ec = LoadModule(name, flags, ppModule);
    if (SUCCEEDED(ec) || E_INVALID_ARGUMENT == ec) return ec;

#ifdef CACHEMANAGER
    ICARCacheMgr *pICARCacheMgr = NULL;

    // It is Cache Manager
    if (!wcscmp((wchar_t*)name,
                L"www.elastos.com.cn/car/cachemgr.dll")) {
        return LoadModule(EZCSTR("cachemgr.dll"),
                flags, ppModule);
    }

    ec = _CSystem_FindRunningObject(L"cachemgr", (PInterface *)&pICARCacheMgr);
    if (FAILED(ec)) {
        return ec;
    }

    ec = pICARCacheMgr->GetPathByURL(GetType_Normal, name, esbpath);
    pICARCacheMgr->Release();
    if (SUCCEEDED(ec)) {
        ec = LoadModule(esbpath, flags, ppModule);
    }
    return ec;
#else
    const wchar_t *pName;
    pName = wcsrchr(name, L'/');
    if (!pName) {
        pName = name;
    }
    else {
        pName++;
    }
    esbpath.Copy(pName);
    return LoadModule(esbpath, flags, ppModule);
#endif
}

ELAPI _CThread_New(
            PThreadMain pEntry,
            void *pArg,
            ThreadCreationFlags flags,
            IThread **ppThread)
{
    IThread *pThread;

    ECode ec = GetIKernel()->CreateThread((Address)ThreadEntry, (Int32)pEntry,
            (Int32)pArg, flags, &pThread);

    if (FAILED(ec)) {
        return ec;
	}

	IApplet *pApplet;
	ec = _CApplet_GetCurrent((PInterface *)&pApplet);
	if (SUCCEEDED(ec)) {
        IAppletSystemSpecific *pAppletSpecific = IAppletSystemSpecific::Probe(pApplet);
        assert(pAppletSpecific);
		pAppletSpecific->NotifyThreadCreated(pThread);
		pApplet->Release();
	}

	if (NULL != ppThread) {
	    *ppThread = pThread;
	}
    else {
	    pThread->Release();
	}

    return NOERROR;
}

ELAPI _CThread_AtQuit(
            PThreadQuitRoutine pEntry,
            PVoid pUserData)
{
    if (!pEntry) return E_INVALID_ARGUMENT;

    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (!pContext) {
        pContext = new CThreadQuitContext;
        if (!pContext) {
            return E_OUT_OF_MEMORY;
        }
        pContext->AddRef();
        _CThread_SetLocalObject(TL_QUIT_SLOT, pContext);
    }
    else {
        pContext->Release();
    }

    return pContext->AddQuitRoutine(pEntry, pUserData);
}

ELAPI_(IThread *) _CThread_GetCurrent()
{
    register IThread * pThread;
    _CThread_GetLocalObject(TL_THREAD_INFO_SLOT, (PInterface *)&pThread);
    assert(NULL != pThread);
    pThread->Release();
    return pThread;
}

ELAPI_(void) _CThread_Quit(
            QuitCode quitCode)
{
    IApplet *pApplet;

	ECode ec = _CApplet_GetCurrent((PInterface *)&pApplet);
	IThread *pThread = _CThread_GetCurrent();
	assert(NULL != pThread);
	if (SUCCEEDED(ec)) {
        IAppletSystemSpecific *pAppletSpecific = IAppletSystemSpecific::Probe(pApplet);
        assert(pAppletSpecific);
		pAppletSpecific->NotifyThreadQuit(pThread);
		pApplet->Release();
	}

    // Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    uint_t uStackTop = GetStackTop();
    if (g_uMainThreadStackTop == uStackTop) {
        // Call process exit routines and clean up process static objects
        s_processExitContext.DoAtExit();

        CleanUpAllThreadsLocalSlots();
    }
    else {
        CleanUpThreadLocalSlots(uStackTop);
    }

    SysExitThread(quitCode);
    assert(0);
}

ELAPI _CThread_Sleep(
            Millisecond32 ms,
            WaitResult *pResult)
{
    return GetIKernel()->Sleep(ms, pResult);
}

#ifndef UINT_MAX
#define UINT_MAX    0xffffffff
#endif

ELAPI _CThread_Delay(
            Microsecond32 us)
{
    if (0 == s_uDelayLoopCount) return E_NOT_SUPPORTED;

    UInt32 uMicroseconds = (UInt32)us;
    volatile _ELASTOS Boolean bContinue = TRUE;

    volatile UInt32 u;
    volatile UInt32 uCount;
    register UInt32 uCurrentDelayMicroseconds;

    do {
        uCurrentDelayMicroseconds = UINT_MAX / s_uDelayLoopCount;
        if (uMicroseconds < uCurrentDelayMicroseconds) {
            uCurrentDelayMicroseconds = uMicroseconds;
        }

        u = 0;
        uCount = s_uDelayLoopCount * uCurrentDelayMicroseconds;

        while (bContinue && u < uCount) {
            u++;
        }

        uMicroseconds -= uCurrentDelayMicroseconds;
    } while (0 < uMicroseconds);

    return NOERROR;
}

ELAPI _CThread_Yield()
{
    return GetIKernel()->Yield();
}

ELAPI _CVirtualMemory_Alloc(
            Address baseAddr,
            MemorySize size,
            MemoryMapFlags flags,
            MemoryProtection protect,
            Address *pBaseAddr)
{
#if defined(MEMORYSPY)
	ECode ec = GetIKernel()->VirtualMemoryMap(baseAddr, size, flags, protect, pBaseAddr);
   	if (NOERROR == ec) {
		ec = AddToProcessHash((void *)(*pBaseAddr), size);
		if (NOERROR != ec) {
			_CVirtualMemory_Free(*pBaseAddr, size);
		}
   	}
	return ec;
#else
	return GetIKernel()->VirtualMemoryMap(baseAddr, size, flags, protect, pBaseAddr);
#endif //MEMORYSPY
}

ELAPI _CVirtualMemory_Query(
            Address address,
            Address *pBaseAddr,
            MemorySize *pSize)
{
    return GetIKernel()->MemoryQuery(address, pBaseAddr, pSize);
}

ELAPI _CVirtualMemory_QueryPhysicalBlock(
            Address address,
            Address *pAddress,
            MemorySize *pSize)
{
    return GetIKernel()->MemoryQueryPhysicalBlock(address, pAddress, pSize);
}

ELAPI _CVirtualMemory_SetProtection(
            Address baseAddr,
            MemorySize size,
            MemoryProtection protect)
{
    return GetIKernel()->MemoryProtect(baseAddr, size, protect);
}

ELAPI _CVirtualMemory_Commit(
            Address address)
{
    return GetIKernel()->MemoryCommit(address);
}

ELAPI _CVirtualMemory_CheckProtection(
            Address address,
            MemoryProtection protect,
            Boolean *pIsValid)
{
    return GetIKernel()->MemoryCheck(address, protect, pIsValid);
}

ELAPI _CVirtualMemory_Free(
            Address baseAddr,
            MemorySize size)
{
#if defined(MEMORYSPY)
    ECode ec = GetIKernel()->MemoryUnmap(baseAddr, size);
    if (NOERROR == ec) {
    	RemoveFromProcessHash((void *)baseAddr);
    }
    return ec;
#else
	return GetIKernel()->MemoryUnmap(baseAddr, size);
#endif //MEMORYSPY
}

ELAPI _CVirtualMemory_IoRemap(
            Address virtualAddr,
            MemorySize size,
            Address physicalAddr,
            MemoryMapFlags flags,
            Int32 protect,
            Address *pVirtualAddr)
{
#if defined(MEMORYSPY)
	ECode ec = GetIKernel()->IoRemap(virtualAddr, size, physicalAddr,
                						flags, protect, pVirtualAddr);
   	if (NOERROR == ec) {
		ec = AddToProcessHash((void *)(*pVirtualAddr), size);
		if (NOERROR != ec) {
			_CVirtualMemory_Free(*pVirtualAddr, size);
		}
   	}
	return ec;
#else
    return GetIKernel()->IoRemap(virtualAddr, size, physicalAddr,
                flags, protect, pVirtualAddr);
#endif //MEMORYSPY
}

ELAPI _CMutex_New(
       /* [out] */ IMutex **ppMutex)
{
    return GetIKernel()->CreateMutex(ppMutex);
}

ELAPI _CCondition_New(
       /* [out] */ ICondition **ppCondition)
{
    return GetIKernel()->CreateCondition(ppCondition);
}

ELAPI _CEvent_New(
       /* [in] */ Boolean manualReset,
       /* [in] */ EventState initialState,
       /* [out] */ IEvent **ppEvent)
{
    return GetIKernel()->CreateEvent(manualReset, initialState, ppEvent);
}

ELAPI _CReaderWriterLock_New(
       /* [out] */ IReaderWriterLock **ppRWLock)
{
    return GetIKernel()->CreateReaderWriterLock(ppRWLock);
}

static Void ReleaseKStub(IInterface * pObj)
{
    assert(pObj);
    IProxy * pProxy;
    pProxy = (IProxy*) pObj->Probe(EIID_IProxy);
    if (pProxy) {
        oid_t oid;
        pProxy->GetOid(&oid);
        PContext ctx = ((CObjectProxy *)pProxy)->m_pInterfaces[0].m_pContext;
        DECL_RELEASE_HEADER(header, oid, ctx);
        SysInvoke(oid, FALSE, &header, sizeof(MarshalHeader), NULL, 0);
    }
}

ELAPI _CMutex_NewWithName(
       /* [in] */ WString name,
       /* [out] */ IMutex **ppMutex,
       /* [out] */ Boolean *pAlreadyExists)
{
    Boolean bAlreadyExists;
    ECode ec = GetIKernel()->CreateNamedMutex(name, ppMutex, &bAlreadyExists);
    if (SUCCEEDED(ec)) {
        if (!bAlreadyExists) {
            ReleaseKStub(*ppMutex);
        }
        if (pAlreadyExists) {
            *pAlreadyExists = bAlreadyExists;
        }
    }
    return ec;
}

ELAPI _CCondition_NewWithName(
       /* [in] */ WString name,
       /* [out] */ ICondition **ppCondition,
       /* [out] */ Boolean *pAlreadyExists)
{
    Boolean bAlreadyExists;
    ECode ec = GetIKernel()->CreateNamedCondition(
            name, ppCondition,  &bAlreadyExists);
    if (SUCCEEDED(ec)) {
        if (!bAlreadyExists) {
            ReleaseKStub(*ppCondition);
        }
        if (pAlreadyExists) {
            *pAlreadyExists = bAlreadyExists;
        }
    }
    return ec;
}

ELAPI _CEvent_NewWithName(
       /* [in] */ WString name,
       /* [in] */ Boolean manualReset,
       /* [in] */ EventState initialState,
       /* [out] */ IEvent **ppEvent,
       /* [out] */ Boolean *pAlreadyExists)
{
    Boolean bAlreadyExists;
    ECode ec = GetIKernel()->CreateNamedEvent(
            name, manualReset, initialState, ppEvent, &bAlreadyExists);
    if (SUCCEEDED(ec)) {
        if (!bAlreadyExists) {
            ReleaseKStub(*ppEvent);
        }
        if (pAlreadyExists) {
            *pAlreadyExists = bAlreadyExists;
        }
    }
    return ec;
}

ELAPI _CReaderWriterLock_NewWithName(
       /* [in] */ WString name,
       /* [out] */ IReaderWriterLock **ppRWLock,
       /* [out] */ Boolean *pAlreadyExists)
{
    Boolean bAlreadyExists;
    ECode ec = GetIKernel()->CreateNamedReaderWriterLock(
            name, ppRWLock, &bAlreadyExists);
    if (SUCCEEDED(ec)) {
        if (!bAlreadyExists) {
            ReleaseKStub(*ppRWLock);
        }
        if (pAlreadyExists) {
            *pAlreadyExists = bAlreadyExists;
        }
    }
    return ec;
}

ELAPI _CSharedMemory_New(
       /* [in] */ WString name,
       /* [in] */ MemorySize size,
       /* [in] */ Boolean reserved,
       /* [out] */ ISharedMemory **ppSharedMemory,
       /* [out] */ Boolean *pAlreadyExists)
{
    if (!reserved) {
        return E_INVALID_ARGUMENT;
    }

    Boolean bAlreadyExists;
    ECode ec = GetIKernel()->CreateNamedSharedMemory(
            name, size, reserved, ppSharedMemory, &bAlreadyExists);
    if (SUCCEEDED(ec)) {
        if (!bAlreadyExists) {
            ReleaseKStub(*ppSharedMemory);
        }
        if (pAlreadyExists) {
            *pAlreadyExists = bAlreadyExists;
        }
    }
    return ec;
}

ELAPI _CSystem_CreateSystemEventHandle(
        /* [in] */ SystemEvents interestedEvents, IEvent **ppEvent)
{
    return GetIKernel()->RequestSystemEvent(
            interestedEvents, ppEvent);
}

ELAPI _CHostingManager_Acquire(
        /* [out] */ IHostingManager **ppManager)
{
    return GetIKernel()->GetHostingManager(ppManager);
}

// TODO: Optimized it
//
ELAPI _CSystem_WaitForAnySystemEvent(
        /* [in] */ SystemEvents interestedEvents, SystemEvent *pSystemEvent)
{
    WaitResult wr;
    ECode ec;
    IEvent *pSysEvent;

    ec = GetIKernel()->RequestSystemEvent(
            interestedEvents, &pSysEvent);
    if (FAILED(ec)) return ec;

    do {
        ec = pSysEvent->Wait(&wr, (EventState *)pSystemEvent);
    } while (FAILED(ec));

    pSysEvent->Release();
    return ec;
}

ELAPI _CCriticalSection_Initialize(
        /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    return ((_CCriticalSection *)pCriticalSection)->Initialize();
}

ELAPI_(void) _CCriticalSection_Enter(
        /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Enter();
}

ELAPI _CCriticalSection_TryEnter(
        /* [in] */ CriticalSection *pCriticalSection,
        /* [out] */ Boolean *pEntered)
{
    assert(pCriticalSection);

    return ((_CCriticalSection *)pCriticalSection)->TryEnter(pEntered);
}

ELAPI_(void) _CCriticalSection_Leave(
        /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Leave();
}

ELAPI_(void) _CCriticalSection_Terminate(
        /* [in] */ CriticalSection *pCriticalSection)
{
    assert(pCriticalSection);

    ((_CCriticalSection *)pCriticalSection)->Terminate();
}

EXTERN void InitTLS()
{
    _CCriticalSection_Initialize(&g_tlsLock);
    memset(g_tlsTypes, ThreadLocalSlotType_Free, TLS_TOTAL_SLOTS);
    g_tlsAllocatedList.Initialize();

    g_tlsTypes[TL_SEQUENCED_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_SEQUENCED_SLOT]);

    g_tlsTypes[TL_QUIT_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_QUIT_SLOT]);

    g_tlsTypes[TL_DOMAIN_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_DOMAIN_SLOT]);

    g_tlsTypes[TL_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_CALLBACK_SLOT]);

    g_tlsTypes[TL_THREAD_INFO_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_THREAD_INFO_SLOT]);

    g_tlsTypes[TL_HELPER_INFO_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_HELPER_INFO_SLOT]);

    g_tlsTypes[TL_APPLET_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_APPLET_SLOT]);

    g_tlsTypes[TL_ORG_CALLBACK_SLOT] = ThreadLocalSlotType_Obj;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_ORG_CALLBACK_SLOT]);

    g_tlsTypes[TL_APPLET_DIR_SLOT] = ThreadLocalSlotType_Value;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[TL_APPLET_DIR_SLOT]);
}

EXTERN void UninitTLS()
{
    _CCriticalSection_Terminate(&g_tlsLock);
}

ELAPI _CThread_AcquireLocalSlot(
        /* [in] */ ThreadLocalSlotType slotType,
        /* [out] */ Int32 *pSlotIndex)
{
    Void * pContext = _Elastos_CriticalSection_Enter(&g_tlsLock);

    ECode ec = GetIKernel()->AcquireThreadLocalSlot(slotType, pSlotIndex);
    if (FAILED(ec)) {
        _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);
        return ec;
    }

    g_tlsTypes[*pSlotIndex] = slotType;
    g_tlsAllocatedList.InsertFirst(&g_tlsAllocatedNodes[*pSlotIndex]);

    _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);

    return ec;
}

ELAPI _CThread_RelinquishLocalSlot(
        /* [in] */ Address slotIndex)
{
    BufferOf_<Address, THREAD_MINIMUM_AVAILABLE> eaUsedPtrs;
    Byte tlsType;
    Int32 i, used;

    Void * pContext = _Elastos_CriticalSection_Enter(&g_tlsLock);

    ECode ec = GetIKernel()->RelinquishThreadLocalSlot(
                    slotIndex, &eaUsedPtrs);
    if (FAILED(ec)) {
        _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);
        return ec;
    }

    tlsType = g_tlsTypes[slotIndex];
    g_tlsTypes[slotIndex] = ThreadLocalSlotType_Free;
    g_tlsAllocatedNodes[slotIndex].Detach();

    _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);

    used = eaUsedPtrs.GetUsed();
    if (ThreadLocalSlotType_Mem == tlsType) {
        for (i = 0; i < used; i++) {
            if (NULL != eaUsedPtrs[i]) free((PVoid)eaUsedPtrs[i]);
        }
    }
    else if (ThreadLocalSlotType_Obj == tlsType) {
        for (i = 0; i < used; i++) {
            if (NULL != eaUsedPtrs[i]) {
                ((PInterface)(PVoid)eaUsedPtrs[i])->Release();
            }
        }
    }

    return NOERROR;
}

ELAPI _CThread_SetLocalValue(
        /* [in] */ Int32 slotIndex,
        /* [in] */ TLValue value)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Value != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    ((volatile TLValue *)GetStackTop())[(int)slotIndex - TLS_TOTAL_SLOTS] =
            value;

    return NOERROR;
}

ELAPI _CThread_SetLocalMemory(
        /* [in] */ Int32 slotIndex,
        /* [in] */ PVoid pMem)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Mem != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    PVoid *ppMemSlot =
        ((PVoid *)GetStackTop()) + ((int)slotIndex - TLS_TOTAL_SLOTS);

    if (NULL != *ppMemSlot) free(*ppMemSlot);

    *ppMemSlot = pMem;

    return NOERROR;
}

ELAPI _CThread_SetLocalObject(
        /* [in] */ Int32 slotIndex,
        /* [in] */ PInterface pObj)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Obj != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    PInterface *ppObjSlot =
        ((PInterface *)GetStackTop()) + ((int)slotIndex - TLS_TOTAL_SLOTS);

    if (NULL != *ppObjSlot) (*ppObjSlot)->Release();

    *ppObjSlot = pObj;

    return NOERROR;
}

ELAPI _CThread_GetLocalValue(
        /* [in] */ Int32 slotIndex,
        /* [out] */ TLValue *pValue)
{

    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Value != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    *pValue =
        ((TLValue *)GetStackTop())[(int)slotIndex - TLS_TOTAL_SLOTS];

    return NOERROR;
}

ELAPI _CThread_GetLocalMemory(
        /* [in] */ Int32 slotIndex,
        /* [out] */ PVoid *ppMem)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Mem != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    *ppMem =
        ((PVoid *)GetStackTop())[(int)slotIndex - TLS_TOTAL_SLOTS];

    return NOERROR;
}

ELAPI _CThread_GetLocalObject(
        /* [in] */ Int32 slotIndex,
        /* [out] */ PInterface *ppObj)
{
    if (slotIndex < 0 || slotIndex >= TLS_TOTAL_SLOTS
        || ThreadLocalSlotType_Obj != g_tlsTypes[slotIndex]) {
        return E_INVALID_ARGUMENT;
    }

    *ppObj =
        ((PInterface *)GetStackTop())[(int)slotIndex - TLS_TOTAL_SLOTS];

    if (NULL != *ppObj) (*ppObj)->AddRef();

    return NOERROR;
}

EXTERN UInt32 GetCurrentThreadStackTop()
{
    return GetStackTop();
}

EXTERN void CleanUpThreadLocalSlots(UInt32 uStackTop)
{
    PVoid tlsValues[TLS_TOTAL_SLOTS];
    Byte tlsTypes[TLS_TOTAL_SLOTS];
    PVoid pValue;
    Int32 i, used = 0;

    Void * pContext = _Elastos_CriticalSection_Enter(&g_tlsLock);

    DLinkNode *pNode;
    ForEachDLinkNode(DLinkNode *, pNode, &g_tlsAllocatedList) {
        i = pNode - g_tlsAllocatedNodes;
        if (ThreadLocalSlotType_Mem == g_tlsTypes[i]
            || ThreadLocalSlotType_Obj == g_tlsTypes[i]) {
            pValue = ((PVoid *)uStackTop)[(int)i - TLS_TOTAL_SLOTS];
            if (NULL != pValue) {
                ((PVoid *)uStackTop)[(int)i - TLS_TOTAL_SLOTS] = NULL;
                tlsValues[used] = pValue;
                tlsTypes[used] = g_tlsTypes[i];
                used++;
            }
        }
    }

    _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);

    for (i = 0; i < used; i++) {
        if (ThreadLocalSlotType_Mem == tlsTypes[i]) {
            free(tlsValues[i]);
        }
        else {
            ((PInterface)tlsValues[i])->Release();
        }
    }
}

EXTERN void CleanUpAllThreadsLocalSlots()
{
    BufferOf_<Address, THREAD_MINIMUM_AVAILABLE> eaUsedPtrs;
    BufferOf_<Int32, TLS_TOTAL_SLOTS> eaUsedIndices;
    Byte tlsType;
    Int32 i, j, nIndicesUsed, nPtrsUsed, slotIndex;
    ECode ec;

    Void * pContext = _Elastos_CriticalSection_Enter(&g_tlsLock);

    DLinkNode *pNode;
    ForEachDLinkNode(DLinkNode *, pNode, &g_tlsAllocatedList) {
        eaUsedIndices.Append(pNode - g_tlsAllocatedNodes);
    }

    _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);

    nIndicesUsed = eaUsedIndices.GetUsed();
    for (i = 0; i < nIndicesUsed; i++) {
        pContext = _Elastos_CriticalSection_Enter(&g_tlsLock);

        slotIndex = eaUsedIndices[i];
        tlsType = g_tlsTypes[slotIndex];
        ec = GetIKernel()->CleanUpThreadLocalSlot(slotIndex, &eaUsedPtrs);

        _Elastos_CriticalSection_Leave(&g_tlsLock, pContext);

        if (FAILED(ec)) {
            continue;
        }

        nPtrsUsed = eaUsedPtrs.GetUsed();
        if (ThreadLocalSlotType_Mem == tlsType) {
            for (j = 0; j < nPtrsUsed; j++) {
                if (NULL != eaUsedPtrs[j]) free((PVoid)eaUsedPtrs[j]);
            }
        }
        else if (ThreadLocalSlotType_Obj == tlsType) {
            for (j = 0; j < nPtrsUsed; j++) {
                if (NULL != eaUsedPtrs[j]) {
                    ((PInterface)(PVoid)eaUsedPtrs[j])->Release();
                }
            }
        }
    }
}

EXTERN ECode Reply(
        ECode ec, void *pvOutBuf, size_t uOutBufSize, _ELASTOS Boolean bCleanupTLSlots)
{
    // Call thread quit routines and clean up thread static objects
    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (pContext) {
        pContext->Release();
        pContext->DoAtQuit();
        _CThread_SetLocalObject(TL_QUIT_SLOT, (PInterface)NULL);
    }

    if (bCleanupTLSlots) {
        uint_t uStackTop = GetStackTop();
        assert(g_uMainThreadStackTop != uStackTop);
        CleanUpThreadLocalSlots(uStackTop);
    }

    return SysReply(ec, pvOutBuf, uOutBufSize);
}

ELAPI _CEvent_WaitForAnyEvents(
        /* [in] */ const BufferOf<IEvent *> * events,
        /* [out] */ WaitResult *pResult,
        /* [out] */ Int32 *pIndex,
        /* [out] */ EventState *pState)
{
    return GetIKernel()->WaitForAnyEvents(
                *events, pResult, pIndex, pState);
}

ELAPI _CEvent_TryWaitForAnyEvents(
        /* [in] */ const BufferOf<IEvent *> * events,
        /* [in] */ Millisecond32 timeout,
        /* [out] */ WaitResult *pResult,
        /* [out] */ Int32 *pIndex,
        /* [out] */ EventState *pState)
{
    return GetIKernel()->TryWaitForAnyEvents(
                *events, timeout, pResult, pIndex, pState);
}

ELAPI _CProcess_FlushInstructionCache(
        /* [in] */ Address baseAddr,
        /* [in] */ MemorySize size)
{
    return GetIKernel()->FlushInstructionCache((UInt32)baseAddr, size);
}

ELAPI _Impl_GetStartInfo(
            WStringBuf * pCmdName,
            WStringBuf * pCmdArgs)
{
    if (pCmdName == NULL || !pCmdName->GetCapacity()) {
        return E_INVALID_ARGUMENT;
    }

    return _CProcess_GetCurrent()->GetStartInfo(pCmdName, pCmdArgs);
}

ELAPI _EzGetEnvironmentMutex(
            IMutex **ppEnvMutex)
{
    return GetIKernel()->GetEnvironmentMutex(ppEnvMutex);
}

ELAPI  _EzGetEnvBase(
            wchar_t ***pppwszEnvBase, wchar_t **ppwszDevpath)
{
    *pppwszEnvBase = (wchar_t **)USER_ENVIRONMENT_BASE;
    *ppwszDevpath = (wchar_t *)USER_DEVPATH_BASE;
    return NOERROR;
}

//
// REDIRECT_INFO_BASE is defined in \elastos\inc\elacfg.h
//
#define REDIRECT_ELEMENT_SIZE       512         //0.5KB

ELAPI _EzSetStdDevice(UInt32 stdDeviceNo, WString fileName)
{
    ECode ec = NOERROR;

    if (stdDeviceNo > 2) {
        ec = E_INVALID_ARGUMENT;
    }
    else {
        wchar_t *pwszStdDevice = (wchar_t *)(REDIRECT_INFO_BASE
                            + REDIRECT_ELEMENT_SIZE * stdDeviceNo);
        if (fileName.IsNull()) {
            *pwszStdDevice = L'\0';
        }
        else {
            if (wcslen(fileName) > (REDIRECT_ELEMENT_SIZE / sizeof(wchar_t))) {
                ec = E_OUT_OF_MEMORY;
            }
            else {
                wcscpy(pwszStdDevice, fileName);
            }
        }
    }

    return ec;
}

ELAPI _EzGetStdDevice(UInt32 stdDeviceNo, WChar ** ppFileName)
{
    ECode ec = NOERROR;

    if (stdDeviceNo > 2 || !ppFileName) {
        ec = E_INVALID_ARGUMENT;
    }
    else {
        wchar_t *pwszStdDevice = (wchar_t *)(REDIRECT_INFO_BASE
                    + REDIRECT_ELEMENT_SIZE * stdDeviceNo);
        if (*pwszStdDevice == L'\0') {
            *ppFileName = NULL;
        }
        else {
            *ppFileName = (WChar *)pwszStdDevice;
        }
    }

    return ec;
}

static Void SetErrorInfo(CONST Void * pBuf, UInt32 size, UInt32 width)
{
    assert(pBuf);

    size *= width;

    ErrorInfoHeader * pHeader
        = (ErrorInfoHeader *)(Void *)(GetStackTop() - TLS_SIZE
                                                    - ERROR_INFO_SIZE);

    size = MIN(size, ERROR_INFO_SIZE - sizeof(ErrorInfoHeader) - width);

    pHeader->m_uSize = sizeof(ErrorInfoHeader) + size + width;

    memcpy(pHeader + 1, pBuf, size);
    memset((Void *)((UInt32)(pHeader + 1) + size), 0, width);
}

ELAPI_(PVoid) GetErrorInfo()
{
    return (Void *)(GetStackTop() - TLS_SIZE - ERROR_INFO_SIZE
                                            + sizeof(ErrorInfoHeader));
}

ELAPI_(WString) _CErrorReport_GetWString()
{
    return (wchar_t *)GetErrorInfo();
}

ELAPI_(AString) _CErrorReport_GetAString()
{
    return (char *)GetErrorInfo();
}

ELAPI_(AString) _CErrorReport_GetUrl()
{
    return (char *)GetErrorInfo();
}

ELAPI _CErrorReport_SetWString(
    /* [in] */ WString string)
{
    if (string.IsNull()) string = L"";

    SetErrorInfo(string, wcslen(string), sizeof(WChar));

    return E_ERROR_STRING;
}

ELAPI _CErrorReport_SetAString(
    /* [in] */ AString string)
{
    if (string.IsNull()) string = "";

    SetErrorInfo(string, strlen(string), sizeof(AChar));

    return E_ERROR_STRING_A;
}

ELAPI _CErrorReport_SetUrl(
    /* [in] */ AString url)
{
    if (url.IsNull()) url = "";

    SetErrorInfo(url, strlen(url), sizeof(AChar));

    return E_ERROR_URL;
}

ELAPI _CObject_ReleaseAtProcessExit(PInterface pObject)
{
    if (!pObject) return E_INVALID_ARGUMENT;

    return s_processExitContext.AddObject(pObject);
}

ELAPI _CObject_ReleaseAtThreadQuit(
        /* [in] */ PInterface pObject)
{
    if (!pObject) return E_INVALID_ARGUMENT;

    CThreadQuitContext * pContext;
    _CThread_GetLocalObject(TL_QUIT_SLOT, (PInterface *)&pContext);
    if (!pContext) {
        pContext = new CThreadQuitContext;
        if (!pContext) {
            return E_OUT_OF_MEMORY;
        }
        pContext->AddRef();
        _CThread_SetLocalObject(TL_QUIT_SLOT, pContext);
    }
    else {
        pContext->Release();
    }

    return pContext->AddObject(pObject);
}

ELAPI _CObject_ReleaseAtAppletFinish(
    /* [in] */ PInterface pObject)
{
    ECode ec;
    PInterface pAppletContext = NULL;
    if (!pObject) return E_INVALID_ARGUMENT;

    ec = _Impl_CAppletContext_GetCurrent(&pAppletContext);
    if (FAILED(ec) && E_NOT_IN_ANY_APPLET != ec) return ec;

    if (pAppletContext) pAppletContext->Release();
    else return _CObject_ReleaseAtProcessExit(pObject);

    return ((CAppletContext*)pAppletContext)->AddObject(pObject);
}

ELAPI _CObject_EnterContext(PInterface pObject, PContext pContext)
{
    return pContext->Aggregate(AggrType_ObjectEnter, pObject);
}

ELAPI _CObject_LeaveContext(PInterface pObject, PContext pContext)
{
    return pContext->Aggregate(AggrType_ObjectLeave, pObject);
}

ELAPI_(Boolean) _Impl_CheckHelperInfoFlag(Flags32 flag)
{
    Flags32 uFlag = 0;
    ECode ec;

    ec = _CThread_GetLocalValue(TL_HELPER_INFO_SLOT, (TLValue*)&uFlag);
    assert(SUCCEEDED(ec));

    if (uFlag & flag) return TRUE;
    else return FALSE;
}

ELAPI_(void) _Impl_SetHelperInfoFlag(Flags32 flag, Boolean bValue)
{
    Flags32 uFlag = 0;
    ECode ec;

    ec = _CThread_GetLocalValue(TL_HELPER_INFO_SLOT, (TLValue*)&uFlag);
    assert(SUCCEEDED(ec));

    if (bValue) {
        uFlag |= flag;
    }
    else {
        uFlag &= ~flag;
    }

    ec = _CThread_SetLocalValue(TL_HELPER_INFO_SLOT, (TLValue)uFlag);
    assert(SUCCEEDED(ec));
}

ELAPI _Impl_EnterProtectedZone()
{
    _Impl_SetHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE, TRUE);
    return NOERROR;
}

ELAPI _Impl_LeaveProtectedZone()
{
    _Impl_SetHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE, FALSE);
    return NOERROR;
}

ELAPI _Impl_InsideProtectedZone()
{
    if (!_Impl_CheckHelperInfoFlag(HELPER_ENTERED_PROTECTED_ZONE)) {
        return E_NOT_IN_PROTECTED_ZONE;
    }

    return NOERROR;
}

ELAPI_(void) _Elastos_SequencedContext_Enter(
        /* [in] */ void *pContext)
{
    if (NULL != pContext) {
        _CCriticalSection_Enter((CRITICAL_SECTION *)pContext);
        _CThread_SetLocalValue(TL_SEQUENCED_SLOT, pContext);
    }
}

ELAPI_(void *) _Elastos_SequencedContext_Leave()
{
    CRITICAL_SECTION *pLock = NULL;
    _CThread_GetLocalValue(TL_SEQUENCED_SLOT, (TLValue *)&pLock);
    if (NULL != pLock) {
        _CThread_SetLocalValue(TL_SEQUENCED_SLOT, NULL);
        _CCriticalSection_Leave(pLock);
    }
    return pLock;
}


ELAPI_(void *) _Elastos_CriticalSection_Enter(
        /* [in] */ CRITICAL_SECTION *pCriticalSection)
{
    assert(pCriticalSection != NULL);

    void * pContext = _Elastos_SequencedContext_Leave();

    _CCriticalSection_Enter(pCriticalSection);

    return pContext;
}

ELAPI_(void) _Elastos_CriticalSection_Leave(
        /* [in] */ CRITICAL_SECTION *pCriticalSection,
        /* [in] */ void *pContext)
{
    assert(pCriticalSection != NULL);

    _CCriticalSection_Leave(pCriticalSection);

    _Elastos_SequencedContext_Enter(pContext);
}

ELAPI_(_CMapNode*) _Impl_CMap_AllocNode(WString key, WString value)
{
    Int32 nKeyLen = (key.GetLength() + 1) * sizeof(WChar);
    Int32 nValueLen = (value.GetLength() + 1) * sizeof(WChar);
    Int32 nSize = sizeof(_CMapNode) + nKeyLen + nValueLen;

    PByte pBuf = new Byte[nSize];
    if (pBuf == NULL) return NULL;

    _CMapNode* pNode = (_CMapNode*) new (pBuf) _CMapNode;

    pNode->m_pwcsKey = (WChar*)(pBuf + sizeof(_CMapNode));
    pNode->m_pwcsValue =(WChar*)(pBuf + sizeof(_CMapNode) + nKeyLen);

    wcscpy(pNode->m_pwcsKey, key);
    wcscpy(pNode->m_pwcsValue, value);

    return pNode;
}

ELAPI_(void) _Impl_CMap_FreeNode(_CMapNode* pNode)
{
    delete [] (PByte) pNode;
}
